home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / What's New? / Development Kits / USBDDK_v1.0.1_updated / Examples / USBSampleStorageDriver / SampleStorageDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-29  |  38.3 KB  |  1,133 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        StorageClassDriver.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13.  
  14.  
  15.  
  16. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  17.     includes
  18.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  19. #include <Devices.h>
  20. #include <DriverServices.h>
  21. #include <Interrupts.h>
  22. #include <LowMem.h>
  23. #include <Folders.h>
  24. #include <MacTypes.h>
  25. #include <CodeFragments.h>
  26.  
  27. #include <USB.h>
  28.  
  29. #include "SampleStorageDriverAPI.h"
  30. #include "SampleStorageDeviceID.h"
  31. #include "SampleStorageDriver.h"
  32.  
  33.  
  34.  
  35. extern TheStorageClassDispatchTable;
  36.  
  37.  
  38. enum
  39. {
  40.     kCString = 0,                // StateStr, USBStatusStr selector
  41.     kPString                        // StateStr, USBStatusStr selector
  42. };
  43.  
  44. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  45.     globals
  46.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  47. static             Boolean                            gBeenThereDoneThat = false;    // Flag indicating if this driver has been called before
  48.  
  49. static            Boolean                            gConfigured = false;                // No calls to dispatch table until this is true.
  50.  
  51. static            UInt32                            gConfigureStatus;                    // Current state of cinfiguration
  52.  
  53. static            Boolean                            gOKToRemoval = true;            // Used in StorageClassDriverNotifyProc to prevent removal by expert
  54.  
  55. static struct    StorageClassInfo                gStorageClassInfo;                // Holds all of the common items
  56.     
  57. static struct    StorageClassTransactionPB    gInterruptPB;                        // Used only for the interrupt pipe
  58.  
  59. static struct    StorageClassStatusPB            gGetStatusPB;                        // Used only for the USB Get Status request
  60.  
  61. static struct    StorageClassControlPB        gControlPB;                            // Used only for aborting a R/W transaction
  62.  
  63. static struct    StorageClassTransactionPB    gCommandPB;                            // Used only by StorageClassDriverExecuteCommand
  64.  
  65. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  66.     prototypes
  67.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  68.  
  69. static void InitParamBlock(USBDeviceRef theDeviceRef, USBPB* paramblock);
  70.  
  71. static Boolean    ImmediateError(OSStatus err);
  72.  
  73. static void    StorageDeviceConfigureCompletion(USBPB* pb);
  74.  
  75. static void    StorageDeviceInitiateConfiguration(USBPB* pb);
  76.  
  77. static OSStatus StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr );
  78.  
  79. static OSStatus StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr );
  80.  
  81. // Completion routines
  82.  
  83. static void ReadBlockCompletion(USBPB* usbPB);
  84.  
  85. static void WriteBlockCompletion(USBPB* usbPB);
  86.  
  87. static void ExecuteCommandCompletion(USBPB* usbPB);
  88.  
  89. static void ExecuteBufferedCommandCompletion(USBPB* usbPB);
  90.  
  91. static void GetStatusCompletion(USBPB* usbPB);
  92.  
  93. static void AbortTransactionCompletion(USBPB* usbPB);
  94.  
  95. //****************************************************************************************************
  96.  
  97. #if DEBUG
  98.  
  99. static void
  100. HexStr(    unsigned long    v,
  101.             unsigned char    *p )
  102. {
  103.     int    shift;
  104.     
  105.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  106.     {
  107.         char c = (v >> shift) & 0x0F;
  108.         *p++ = c + (c > 9? ('A'-10): '0');
  109.     }
  110. }
  111.  
  112. static unsigned char *
  113. USBStatusStr(    OSStatus    usbStatus,
  114.                     int        kind )
  115. {
  116.     unsigned char *p;
  117.  
  118.     switch ( usbStatus )
  119.     {
  120.         case    kUSBInternalErr:                    p = "\p" kStrStorageClass "Internal error"; break;
  121.         case    kUSBUnknownDeviceErr:            p = "\p" kStrStorageClass "Unknown device"; break;
  122.         case    kUSBUnknownPipeErr:                 p = "\p" kStrStorageClass "Unknown pipe"; break;
  123.         case    kUSBTooManyPipesErr:                p = "\p" kStrStorageClass "Too many pipes"; break;
  124.         case    kUSBIncorrectTypeErr:            p = "\p" kStrStorageClass "Incorrect type"; break;
  125.         case    kUSBRqErr:                            p = "\p" kStrStorageClass "Request error"; break;
  126.         case    kUSBUnknownRequestErr:            p = "\p" kStrStorageClass "Unknown request"; break;
  127.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrStorageClass "Too many transactions"; break;
  128.         case    kUSBAlreadyOpenErr:                p = "\p" kStrStorageClass "Already open"; break;
  129.         case    kUSBNoDeviceErr:                    p = "\p" kStrStorageClass "No device"; break;
  130.         case    kUSBDeviceErr:                        p = "\p" kStrStorageClass "Device error"; break;
  131.         case    kUSBOutOfMemoryErr:                p = "\p" kStrStorageClass "Out of memory"; break;
  132.         case    kUSBNotFound:                        p = "\p" kStrStorageClass "USB Not found"; break;
  133.         case    kUSBLinkErr:                        p = "\p" kStrStorageClass "Link Err"; break;
  134.         case    kUSBCRCErr:                            p = "\p" kStrStorageClass "Comms/Device err, bad CRC";  break;        
  135.         case    kUSBBitstufErr:                    p = "\p" kStrStorageClass "Comms/Device err, bitstuffing"; break;        
  136.         case    kUSBDataToggleErr:                p = "\p" kStrStorageClass "Comms/Device err, Bad data toggle"; break;        
  137.         case    kUSBEndpointStallErr:            p = "\p" kStrStorageClass "Device didn't understand"; break;        
  138.         case    kUSBNotRespondingErr:            p = "\p" kStrStorageClass "No device, device hung"; break;        
  139.         case    kUSBPIDCheckErr:                    p = "\p" kStrStorageClass "Comms/Device err, PID CRC error"; break;        
  140.         case    kUSBWrongPIDErr:                    p = "\p" kStrStorageClass "Comms/Device err, Bad or wrong PID"; break;        
  141.         case    kUSBOverRunErr:                    p = "\p" kStrStorageClass "Packet too large or more data than buffer"; break;        
  142.         case    kUSBUnderRunErr:                    p = "\p" kStrStorageClass "Less data than buffer"; break;        
  143.         case    kUSBRes1Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  144.         case    kUSBRes2Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  145.         case    kUSBBufOvrRunErr:                    p = "\p" kStrStorageClass "Buffer over run error"; break;        
  146.         case    kUSBBufUnderRunErr:                p = "\p" kStrStorageClass "Buffer under run error"; break;        
  147.         case    kUSBNotSent1Err:                    p = "\p" kStrStorageClass "Transaction not sent1"; break;        
  148.         case    kUSBNotSent2Err:                    p = "\p" kStrStorageClass "Transaction not sent2"; break;    
  149.         default:
  150.             p = "\p" kStrStorageClass "Unknown error nnnnnnnn";
  151.             HexStr( usbStatus, p + *p - 8 + 1 );
  152.             break;
  153.     }
  154.     
  155.     return kind == kPString? p: p + 1;
  156. }
  157.  
  158.  
  159. static unsigned char*
  160. StateStr(    OSStatus    refCon,
  161.                 int        kind )
  162. {
  163.     unsigned char *p;
  164.  
  165.     refCon &= ~(kCompletionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
  166.     switch ( refCon )
  167.     {        
  168.         case kSetConfig:                                    p = kStrStorageClass "kSetConfig"; break;
  169.         case kGetFullConfiguration0:                    p = kStrStorageClass "kGetFullConfiguration0"; break;
  170.         case kGetFullConfiguration1:                    p = kStrStorageClass "kGetFullConfiguration1"; break;
  171.         case kFindStorageInterface:                    p = kStrStorageClass "kFindStorageInterface"; break;
  172.         case kStorageConfigureInterface:                p = kStrStorageClass "kStorageConfigureInterface"; break;
  173.         
  174.         case kNewInterfaceRef:                            p = kStrStorageClass "kNewInterfaceRef"; break;
  175.         case kStorageFindInterruptPipe:                p = kStrStorageClass "kStorageFindInterruptPipe"; break;
  176.         case kStorageFindBulkInPipe:                    p = kStrStorageClass "kStorageFindBulkInPipe"; break;
  177.         case kStorageFindBulkOutPipe:                    p = kStrStorageClass "kStorageFindBulkOutPipe"; break;
  178.                 
  179.         case kStorageReadInterrupt:                    p = kStrStorageClass "kStorageReadInterrupt"; break;
  180.         
  181.         case kStorageInitiateBulkWrite:                p = kStrStorageClass "kStorageInitiateBulkWrite"; break;
  182.         case kStorageBulkWriteComplete:                p = kStrStorageClass "kStorageBulkWriteComplete"; break;
  183.         case kStorageInitiateBulkRead:                p = kStrStorageClass "kStorageInitiateBulkRead"; break;
  184.         case kStorageBulkIOComplete:                    p = kStrStorageClass "kStorageBulkIOComplete"; break;
  185.         
  186.         case kStorageExecuteCommand:                    p = kStrStorageClass "kStorageExecuteCommand"; break;
  187.         case kStorageExecuteCommandCompletion:        p = kStrStorageClass "kStorageExecuteCommandCompletion"; break;
  188.         case kStorageGetStatus:                            p = kStrStorageClass "kStorageGetStatus"; break;
  189.         case kStorageGetStatusBulkRead:                p = kStrStorageClass "kStorageGetStatusBulkRead"; break;
  190.         
  191.         case kStorageReadFirmwareVersion:            p = kStrStorageClass "kStorageReadFirmwareVersion"; break;
  192.  
  193.         default:
  194.             p = "\pUnknown state nnnnnnnn";
  195.             HexStr( refCon, p + *p - 8 + 1 );
  196.             break;
  197.     }
  198.     return kind == kPString? p: p + 1;    
  199. }
  200. #endif
  201.  
  202. static unsigned char
  203. HiHex( int v )
  204. {
  205.     unsigned char    hinibble = (v >> 4) & 0x0f;
  206.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  207. }
  208.  
  209.  
  210. static unsigned char
  211. LoHex( int v )
  212. {
  213.     unsigned char    lonibble = v & 0x0f;
  214.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  215. }
  216.  
  217.  
  218. static void
  219. InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
  220. {
  221.     paramblock->usbReference =    theDeviceRef;
  222.     paramblock->pbVersion =        kUSBCurrentPBVersion;
  223.     paramblock->pbLength =        sizeof(USBPB);
  224.     paramblock->usbWIndex =        0;             
  225.     paramblock->usbBuffer =        nil;        
  226.     paramblock->usbStatus =        noErr;
  227.     paramblock->usbReqCount =    0;
  228.     paramblock->usbWValue =        0;
  229.     paramblock->usbFlags =        0;
  230. }
  231.  
  232.  
  233. static Boolean
  234. ImmediateError(OSStatus err)
  235. {
  236.     return((err != kUSBPending) && (err != noErr) );
  237. }
  238.  
  239.  
  240. OSStatus
  241. GetUSBVersion(UInt32* usbVersion)
  242. {
  243. OSStatus result;
  244.  
  245.     result = Gestalt('usbv', usbVersion);
  246.     
  247.     return result;
  248. }
  249.  
  250.  
  251. OSErr
  252. GetInterfaceDescriptor(    LogicalAddress pConfigDesc,
  253.                                 UInt32 ReqInterface,
  254.                                 USBInterfaceDescriptorPtr * hInterfaceDesc)
  255. {
  256. UInt32                            totalLength;
  257. void *                            pEndOfDescriptors;
  258. USBInterfaceDescriptorPtr    pMyIntDesc;
  259. USBDescriptorHeaderPtr        pCurrentDesc;
  260. UInt32                            anAddress,
  261.                                     anOffset;
  262.  
  263.     totalLength =            ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength;
  264.     pEndOfDescriptors =    (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  265.     pCurrentDesc =            (USBDescriptorHeaderPtr)pConfigDesc;        // point the currentdesc to the start of the config space
  266.     
  267.     while (pCurrentDesc < pEndOfDescriptors)                                // as long as we haven't exhausted all the descriptors
  268.     {
  269.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)        // look at the current descriptor
  270.         {
  271.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;        // if it's an interface descriptor
  272.             if (pMyIntDesc->interfaceNumber == ReqInterface)            // see if it's the request descriptor
  273.             {
  274.                 *hInterfaceDesc = pMyIntDesc;                                    // if it is, then return with hInterfaceDesc set to the
  275.                 return kUSBNoErr;                                                    // current descriptor pointer
  276.             }
  277.         }
  278.         anAddress =        (unsigned long) pCurrentDesc;                        // Nope, that either wasn't an interface descriptor
  279.         anOffset  =        (unsigned long) pCurrentDesc->length;
  280.         anAddress +=    anOffset;
  281.         pCurrentDesc =    (USBDescriptorHeaderPtr) anAddress;
  282.     }                                                                                    // or it was, but not the droid we're looking for.
  283.     return -1;
  284. }
  285.  
  286. //****************************************************************************************************
  287. //
  288. //        StorageClassDriverAPI.c calls end up here...
  289. //
  290. //****************************************************************************************************
  291.  
  292. OSStatus
  293. StorageClassDriverInitialize(void)
  294. {
  295.     return noErr;
  296. }
  297.  
  298.  
  299. OSStatus
  300. StorageClassDriverControl(    UInt32    theControlSelector,
  301.                                     void        *theControlData)
  302. {
  303. #pragma unused (theControlData)
  304.  
  305. OSStatus        status;
  306.  
  307.     switch (theControlSelector)
  308.     {
  309.         case kControlDisableRemoval:
  310.             gOKToRemoval = false;
  311.             status = noErr;
  312.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlDisableRemoval", 0) );
  313.             break;
  314.             
  315.         case kControlEnableRemoval:
  316.             gOKToRemoval = true;
  317.             status = noErr;
  318.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlEnableRemoval", 0) );
  319.             break;
  320.         
  321.         default:
  322.             status = controlErr;
  323.             break;
  324.     }    
  325.     return status;
  326. }
  327.  
  328.  
  329. OSStatus
  330. StorageClassDriverStatus(    UInt32    theInfoSelector,
  331.                                     void        *theInfo)
  332. {
  333. OSStatus        status;
  334.  
  335.     switch (theInfoSelector)
  336.     {
  337.         case kStatusConfiguration:                        // Return the current confifuration status
  338.             *((UInt32*) theInfo) = gConfigureStatus;
  339.             status = noErr;
  340.             break;
  341.             
  342.         case kStatusDeviceStatus:
  343.             status = StorageClassDriverGetStatus( (StorageStatusPBPtr) theInfo );
  344.             break;
  345.         
  346.         case kStatusRemovalStatus:
  347.             *((Boolean*) theInfo) = gOKToRemoval;
  348.             status = noErr;
  349.             break;
  350.             
  351.         default:
  352.             status = statusErr;
  353.             break;
  354.     }    
  355.     return status;
  356. }
  357.  
  358.  
  359. // All device requests come through here
  360. OSStatus
  361. StorageClassDriverExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  362. {
  363. OSStatus            myErr;
  364. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverExecuteCommand", 0) );
  365.  
  366.     // Make sure we have been able to configure the device
  367.     if (gConfigured == false)
  368.     {
  369.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  370.         return kNotConfigured;
  371.     }
  372.         
  373.     // check if we already have a read in progress, if so return error.
  374.     if (gCommandPB.busy == true)
  375.     {
  376.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand busy", 0) );
  377.         return kCommandBusyError;
  378.     }
  379.     
  380.     cmdPBPtr->status = kRequestPending;
  381.  
  382.     BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  383.         
  384.     gCommandPB.busy = true;
  385.  
  386.     InitParamBlock(gStorageClassInfo.interfaceRef, &gCommandPB.usbPB);
  387.     
  388.     // Get a local copy of the callers cdb
  389.     BlockCopy(&cmdPBPtr->cdb[0], &gCommandPB.cdb[0], kCDBSize);
  390.     
  391.     gCommandPB.flags = cmdPBPtr->flags;
  392.     
  393.     gCommandPB.userPBPtr = (StorageBlockRWPB*) cmdPBPtr;                // Save the ptr to the callers PB
  394.     
  395.     gCommandPB.usbPB.usbBMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  396.     
  397.     gCommandPB.usbPB.usbBRequest =        0;
  398.     gCommandPB.usbPB.usbWValue =            0;
  399.     gCommandPB.usbPB.usbWIndex =            0;
  400.     
  401.     gCommandPB.usbPB.usbBuffer =            (Ptr)&gCommandPB.cdb[0];
  402.     gCommandPB.usbPB.usbReqCount =        kCDBSize;
  403.     gCommandPB.usbPB.usbFlags =            0;
  404.         
  405.     gCommandPB.usbPB.usbRefcon =            kStorageExecuteCommand;
  406.     
  407.     gCommandPB.usbPB.usbCompletion =        (USBCompletion)ExecuteCommandCompletion;                // Don't use double buffering for builk I/O
  408.         
  409.     myErr = USBDeviceRequest(&gCommandPB.usbPB);
  410.             
  411.     return myErr;
  412. }
  413.  
  414. static void ExecuteCommandCompletion(USBPB* usbPB)
  415. {
  416. OSStatus                            myErr;
  417. StorageExecuteCommandPBPtr    cmdPBPtr;
  418.  
  419.     // Retrieve the callers pb
  420.     cmdPBPtr = (StorageExecuteCommandPBPtr) gCommandPB.userPBPtr;
  421.         
  422. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 5 ) );
  423.  
  424.     switch(usbPB->usbRefcon)
  425.     {
  426.         case kStorageExecuteCommand:        // Device request completion
  427.             // If there is to be no data transfer then we are done and can return to the caller
  428.             if (gCommandPB.flags & kStorageNoData)
  429.             {
  430.                 // Clear stalled control pipe
  431.                 if (usbPB->usbStatus != noErr)
  432.                 {
  433.                     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageExecuteCommand error. usbStatus:" , usbPB->usbStatus ) );
  434.                     USBClearPipeStallByReference(usbPB->usbReference);
  435.                 }
  436.                 cmdPBPtr->status = usbPB->usbStatus;
  437.                                 
  438.                 gCommandPB.busy = false;
  439.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  440.                 
  441.                 break;
  442.             }
  443.             // Setup the usb pb for either bulk in or out
  444.             if (gCommandPB.flags & kStorageDataIn)
  445.                 InitParamBlock(gStorageClassInfo.readPipeRef, usbPB);
  446.             else if (gCommandPB.flags & kStorageDataOut)
  447.                 InitParamBlock(gStorageClassInfo.writePipeRef, usbPB);
  448.                             
  449.             usbPB->usbReqCount =        cmdPBPtr->expectedCount;
  450.             usbPB->usbRefcon =        kStorageBulkIOComplete;
  451.             usbPB->usbActCount =        0;
  452.             usbPB->usbBuffer =        cmdPBPtr->userBuffer;
  453.             usbPB->usbCompletion =    (USBCompletion)ExecuteCommandCompletion;
  454.             
  455.             // Start a bulk in or out transaction
  456.             if (gCommandPB.flags & kStorageDataIn)
  457.                 myErr = USBBulkRead(&gCommandPB.usbPB);
  458.             else if (gCommandPB.flags & kStorageDataOut)
  459.                 myErr = USBBulkWrite(&gCommandPB.usbPB);
  460.             
  461.             if    (ImmediateError(myErr))
  462.             {
  463.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageExecuteCommand - immediate error", myErr) );
  464.                 cmdPBPtr->actualCount =    usbPB->usbActCount;
  465.                 cmdPBPtr->status = myErr;
  466.                 gCommandPB.busy = false;
  467.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  468.             }
  469.             break;
  470.         
  471.         case kStorageBulkIOComplete:
  472.         
  473.             cmdPBPtr->actualCount =    usbPB->usbActCount;                // Update the users byte count
  474.             cmdPBPtr->status =        usbPB->usbStatus;                    // and status
  475.             
  476.             if (usbPB->usbStatus != noErr)                                // Clear a possible pipe stall
  477.             {
  478.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageBulkIOComplete error. usbStatus:" , usbPB->usbStatus ) );
  479.                 USBClearPipeStallByReference(usbPB->usbReference);
  480.             }
  481.             
  482.             gCommandPB.busy = false;
  483.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  484.             break;
  485.             
  486.         default:
  487.             IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: ExecuteCommandCompletion - unknown state!", 5) );
  488.             cmdPBPtr->actualCount =    0;
  489.             cmdPBPtr->status = kUSBInternalErr;
  490.                         
  491.             gCommandPB.busy = false;
  492.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  493.             break;
  494.     }
  495. }
  496.  
  497. OSStatus
  498. StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr )
  499. {
  500. OSStatus    myErr;
  501.     
  502.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverGetStatus", 0) );
  503.  
  504.     // Make sure we have been able to configure the device
  505.     if (gConfigured == false)
  506.     {
  507.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  508.         return kNotConfigured;
  509.     }
  510.         
  511.     // check if we already have a status request in progress, if so return error.
  512.     if (gGetStatusPB.busy == true)
  513.     {
  514.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverGetStatus busy", 0) );
  515.         return kCommandBusyError;
  516.     }
  517.     
  518.     BlockZero(&gGetStatusPB, sizeof(StorageClassStatusPB));
  519.     
  520.     gGetStatusPB.busy = true;
  521.     
  522.     gGetStatusPB.userPBPtr = statusPBPtr;
  523.     
  524.     InitParamBlock(gStorageClassInfo.interfaceRef, &gGetStatusPB.usbPB);
  525.             
  526.     gGetStatusPB.usbPB.usbBMRequestType =    USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);            
  527.     
  528.     gGetStatusPB.usbPB.usbBRequest =            kUSBRqGetStatus;
  529.     gGetStatusPB.usbPB.usbWIndex =            0;
  530.     gGetStatusPB.usbPB.usbWValue =            0;
  531.     
  532.     gGetStatusPB.usbPB.usbBuffer =            (Ptr)&gGetStatusPB.status[0];
  533.     gGetStatusPB.usbPB.usbReqCount =            kStatusSize;
  534.     gGetStatusPB.usbPB.usbFlags =                0;
  535.         
  536.     gGetStatusPB.usbPB.usbRefcon =            kStorageGetStatus;
  537.     gGetStatusPB.usbPB.usbCompletion =        (USBCompletion)GetStatusCompletion;
  538.             
  539.     myErr = USBDeviceRequest(&gGetStatusPB.usbPB);
  540.             
  541.     return myErr;
  542. }
  543.  
  544.  
  545.  
  546. static void GetStatusCompletion(USBPB* usbPB)
  547. {
  548. StorageStatusPBPtr    userPBPtr;
  549.     
  550.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 6 ) );
  551.     
  552.     // Retrieve the callers pb
  553.     userPBPtr = (StorageStatusPBPtr) gGetStatusPB.userPBPtr;
  554.         
  555.     userPBPtr->status =                usbPB->usbStatus;
  556.     userPBPtr->deviceStatus[0] =    gGetStatusPB.status[0];
  557.     userPBPtr->deviceStatus[1] =    gGetStatusPB.status[1];
  558.                     
  559.     gGetStatusPB.busy = false;
  560.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  561. }
  562.  
  563.  
  564. OSStatus
  565. StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr )
  566. {
  567. OSStatus            myErr;
  568.  
  569.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverAbortTransaction", 0) );
  570.  
  571.     // Make sure we have been able to configure the device
  572.     if (gConfigured == false)
  573.     {
  574.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction not configured", 0) );
  575.         return kNotConfigured;
  576.     }
  577.         
  578.     // check if we already have a status request in progress, if so return error.
  579.     if (gControlPB.busy == true)
  580.     {
  581.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction busy", 0) );
  582.         return kCommandBusyError;
  583.     }
  584.     
  585.     BlockZero(&gControlPB, sizeof(StorageControlPB));
  586.     
  587.     gControlPB.busy = true;
  588.     
  589.     gControlPB.userPBPtr = controlPBPtr;
  590.     
  591.     InitParamBlock(gStorageClassInfo.interfaceRef, &gControlPB.usbPB);
  592.             
  593.     gControlPB.usbPB.usbBMRequestType =    0x02;            // Clear feature        
  594.     
  595.     gControlPB.usbPB.usbBRequest =        kUSBRqClearFeature;
  596.     
  597.     if (controlPBPtr->selector == 0)                        // Abort read pipe
  598.         gControlPB.usbPB.usbWIndex =        0x82;
  599.     else                                                            // Abort write pipe
  600.         gControlPB.usbPB.usbWIndex =        0x01;
  601.         
  602.     gControlPB.usbPB.usbWValue =            0;                // 0 = clear endpoint stall
  603.     
  604.     gControlPB.usbPB.usbBuffer =            nil;
  605.     gControlPB.usbPB.usbReqCount =        0;
  606.     gControlPB.usbPB.usbFlags =            0;
  607.         
  608.     gControlPB.usbPB.usbRefcon =            kStorageGetStatus;
  609.     gControlPB.usbPB.usbCompletion =        (USBCompletion)AbortTransactionCompletion;
  610.             
  611.     myErr = USBDeviceRequest(&gControlPB.usbPB);
  612.             
  613.     return myErr;
  614. }
  615.  
  616.  
  617.  
  618. static void AbortTransactionCompletion(USBPB* usbPB)
  619. {
  620. StorageControlPBPtr    userPBPtr;
  621.     
  622.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 7 ) );
  623.     
  624.     // Retrieve the callers pb
  625.     userPBPtr = (StorageControlPBPtr) gControlPB.userPBPtr;
  626.         
  627.     userPBPtr->status =                usbPB->usbStatus;
  628.                     
  629.     gControlPB.busy = false;
  630.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  631. }
  632.  
  633.  
  634. static void ReadInterruptCompletion(USBPB* usbPB)
  635. {
  636.     gStorageClassInfo.transDepth--;
  637.     
  638.     if (usbPB->usbStatus == kUSBEndpointStallErr)
  639.     {
  640.         USBClearPipeStallByReference(gStorageClassInfo.interruptPipeRef);
  641.     }
  642.     InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  643.  
  644.     usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  645.     usbPB->usbReqCount =        0x02;
  646.     usbPB->usbRefcon =        kStorageReadInterrupt;
  647.     usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  648.     
  649.     StorageDeviceInitiateConfiguration(usbPB);
  650. }
  651.  
  652. void
  653. StorageDeviceInitiateConfiguration(USBPB *usbPB)
  654. {
  655. OSStatus myErr;
  656. StorageClassTransactionPB*    pTransPB = (StorageClassTransactionPB*) usbPB;
  657.  
  658.     gStorageClassInfo.transDepth++;
  659.     
  660.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > kMaxTransitions))
  661.     {
  662.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Illegal Transaction Depth", usbPB->usbRefcon) );
  663.         gConfigureStatus = kConfigureFailed;
  664.     }
  665.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 2 ) );
  666.     
  667.     switch(usbPB->usbRefcon & ~kRetryTransaction)
  668.     {    
  669.         case kGetFullConfiguration0:
  670.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  671.             
  672.             usbPB->usbWIndex =            0;             // First try configuration 0, if it doesn't succeed, then try config 1
  673.             usbPB->usbRefcon |=        kCompletionPending;
  674.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  675.             
  676.             myErr = USBGetFullConfigurationDescriptor(usbPB);
  677.             if(ImmediateError(myErr))
  678.             {
  679.                 gConfigureStatus = kConfigureFailed;
  680.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration (#0) - immediate error", myErr) );
  681.             }
  682.             break;
  683.         
  684.         case kGetFullConfiguration1:
  685.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  686.             
  687.             usbPB->usbWIndex =            1;             // Try configuration 1 (some devices seem to expect config 0, others config 1
  688.             usbPB->usbRefcon |=        kCompletionPending;
  689.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  690.             
  691.             myErr = USBGetFullConfigurationDescriptor(usbPB);
  692.             if(ImmediateError(myErr))
  693.             {
  694.                 gConfigureStatus = kConfigureFailed;
  695.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration (#1) - immediate error", myErr) );
  696.             }
  697.             break;
  698.         
  699.         case kSetConfig:
  700.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  701.             
  702.             usbPB->usbBMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice);
  703.             usbPB->usbBRequest =            kUSBRqSetConfig;
  704.             usbPB->usbWValue =            gStorageClassInfo.pFullConfigDescriptor->configValue;         // Use configuration ID value from descriptor
  705.             usbPB->usbRefcon |=             kCompletionPending;
  706.             
  707.             usbPB->usbCompletion =        (USBCompletion)StorageDeviceConfigureCompletion;
  708.             
  709.             myErr = USBDeviceRequest(usbPB);
  710.             if(ImmediateError(myErr))
  711.             {
  712.                 gConfigureStatus = kConfigureFailed;
  713.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kSetConfig - immediate error", myErr) );
  714.             }
  715.             break;
  716.             
  717.         case kFindStorageInterface:
  718.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  719.             usbPB->usbActCount =        0;
  720.  
  721.             usbPB->usbClassType =    kDriverClassID;
  722.             usbPB->usbSubclass =        kDriverSubClassID;
  723.             usbPB->usbProtocol =        0;
  724.             usbPB->usbWValue =        0;
  725.             usbPB->usbRefcon |=        kCompletionPending;
  726.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  727.             
  728.             myErr = USBFindNextInterface(usbPB);
  729.             if(ImmediateError(myErr))
  730.             {
  731.                 gConfigureStatus = kConfigureFailed;
  732.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kFindStorageInterface - immediate error", myErr) );
  733.             }
  734.             break;
  735.             
  736.         case kNewInterfaceRef:
  737.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  738.             // Note: gStorageClassInfo.usbWIndex will be set to zero by InitParamBlock
  739.             // so set it again to gStorageClassInfo.interfaceIndex before calling USBNewInterfaceRef
  740.             usbPB->usbActCount =        0;
  741.             usbPB->usbWIndex =            gStorageClassInfo.interfaceNumber;
  742.             usbPB->usbRefcon |=        kCompletionPending;
  743.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  744.  
  745.             myErr = USBNewInterfaceRef(usbPB);
  746.             if(ImmediateError(myErr))
  747.             {
  748.                 gConfigureStatus = kConfigureFailed;
  749.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kNewInterfaceRef - immediate error", myErr) );
  750.             }
  751.             break;
  752.                 
  753.         case kStorageConfigureInterface:
  754.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  755.  
  756.             usbPB->usbActCount =        0;
  757.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  758.             usbPB->usbRefcon |=        kCompletionPending;
  759.             
  760.             gStorageClassInfo.interfaceNumber =        0;            // Find First calls 'FindNextInterface' with WIndex = 0
  761.                                                                             // Find Next calls 'FindNextInterface' with WIndex = InterfaceNumber
  762.             
  763.             myErr = USBConfigureInterface(usbPB);
  764.             if (ImmediateError(myErr))
  765.             {
  766.                 gConfigureStatus = kConfigureFailed;
  767.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageConfigureInterface - immediate error", myErr) );
  768.             }
  769.             break;
  770.         
  771.         case kStorageFindInterruptPipe:
  772.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  773.  
  774.             usbPB->usbFlags =            kUSBIn;
  775.             usbPB->usbClassType =    kUSBInterrupt;
  776.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  777.             usbPB->usbRefcon |=        kCompletionPending;
  778.  
  779.             myErr = USBFindNextPipe( usbPB );
  780.             if (ImmediateError(myErr))
  781.             {
  782.                 gConfigureStatus = kConfigureFailed;
  783.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindInterruptPipe - immediate error", myErr) );
  784.                 usbPB->usbRefcon = kReturnFromDriver;
  785.             }
  786.             break;
  787.         
  788.         case kStorageFindBulkInPipe:
  789.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  790.  
  791.             usbPB->usbFlags =            kUSBIn;
  792.             usbPB->usbClassType =    kUSBBulk;
  793.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  794.             usbPB->usbRefcon |=        kCompletionPending;
  795.  
  796.             myErr = USBFindNextPipe( usbPB );
  797.             if (ImmediateError(myErr))
  798.             {
  799.                 gConfigureStatus = kConfigureFailed;
  800.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkInPipe - immediate error", myErr) );
  801.                 usbPB->usbRefcon = kReturnFromDriver;
  802.             }
  803.             break;
  804.         
  805.         case kStorageFindBulkOutPipe:
  806.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  807.  
  808.             usbPB->usbFlags =            kUSBOut;
  809.             usbPB->usbClassType =    kUSBBulk;
  810.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  811.             usbPB->usbRefcon |=        kCompletionPending;
  812.  
  813.             myErr = USBFindNextPipe( usbPB );
  814.             if (ImmediateError(myErr))
  815.             {
  816.                 gConfigureStatus = kConfigureFailed;
  817.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkOutPipe - immediate error", myErr) );
  818.                 usbPB->usbRefcon =    kReturnFromDriver;
  819.             }
  820.             break;
  821.         
  822.         case kStorageReadFirmwareVersion:
  823.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  824.         
  825.             usbPB->usbBMRequestType =    0xc0;
  826.             usbPB->usbBRequest =            1;
  827.             
  828.             usbPB->usbBuffer =            (Ptr)gStorageClassInfo.firmwareVersion;
  829.             usbPB->usbReqCount =            0x02;
  830.             usbPB->usbCompletion =        (USBCompletion)StorageDeviceConfigureCompletion;
  831.             usbPB->usbRefcon |=            kCompletionPending;
  832.                     
  833.             myErr = USBDeviceRequest(usbPB);
  834.             if (ImmediateError(myErr))
  835.             {
  836.                 gConfigureStatus = kConfigureFailed;
  837.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageReadInterrupt - immediate error", myErr) );
  838.             }
  839.             break;
  840.             
  841.         case kStorageReadInterrupt:            
  842.             InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  843.  
  844.             usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  845.             usbPB->usbReqCount =        0x02;
  846.             usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  847.             usbPB->usbRefcon |=        kCompletionPending;
  848.         
  849.             myErr = USBIntRead(usbPB);
  850.             if(ImmediateError(myErr))
  851.             {
  852.                 gConfigureStatus = kConfigureFailed;
  853.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageReadInterrupt - immediate error", myErr) );
  854.             }
  855.             break;
  856.                 
  857.         case kReturnFromDriver:
  858.             break;
  859.             
  860.         default:
  861.             gConfigureStatus = kConfigureFailed;
  862.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Transaction initiated with bad refcon value", usbPB->usbRefcon) );
  863.             usbPB->usbRefcon = kUndefined + kReturnFromDriver;
  864.             break;
  865.     }
  866.     
  867. // At this point the control is returned to the system.  If a USB transaction
  868. // has been initiated, then it will call the Complete procs
  869. // (below) to handle the results of the transaction.
  870. }
  871.  
  872. static void
  873. StorageDeviceConfigureCompletion(USBPB *usbPB)
  874. {
  875. StorageClassTransactionPB*        pTransPB = (StorageClassTransactionPB*) usbPB;
  876. USBInterfaceDescriptorPtr        pInterfaceDescriptor;
  877. UInt32                                i;
  878.  
  879.     gStorageClassInfo.transDepth--;
  880.         
  881.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 3 ) );
  882.     
  883.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > 1))
  884.     {
  885.         gConfigureStatus = kConfigureFailed;
  886.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Illegal Transaction Depth", gStorageClassInfo.transDepth) );
  887.     }
  888.     
  889.     // We should only retry if the error is a USB transaction problem
  890.     // Device errors are handled outside of the state machine.
  891.     if ((usbPB->usbStatus != noErr) && (usbPB->usbStatus != kUSBPending))
  892.     {
  893.         IF_DEBUG( USBExpertStatus(usbPB->usbReference, "\pStorage Driver: Completion Error", usbPB->usbStatus) );
  894.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  895.         usbPB->usbRefcon |= kRetryTransaction;
  896.         gStorageClassInfo.retryCount--;
  897.         if (!gStorageClassInfo.retryCount)
  898.         {
  899.             gConfigureStatus = kConfigureFailed;
  900.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Too many retries", usbPB->usbRefcon) );
  901.             usbPB->usbRefcon = kReturnFromDriver;
  902.             return;
  903.         }
  904.     }
  905.     else
  906.     {
  907.         usbPB->usbRefcon &= ~kRetryTransaction;
  908.         gStorageClassInfo.retryCount = kStorageRetryCount;
  909.     }
  910.  
  911.     if (usbPB->usbRefcon & kCompletionPending)             
  912.     {                                                
  913.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  914.         switch(usbPB->usbRefcon)
  915.         {
  916.             case kGetFullConfiguration0:
  917.             case kGetFullConfiguration1:
  918.                 usbPB->usbRefcon = kSetConfig;
  919.                 gStorageClassInfo.pFullConfigDescriptor = usbPB->usbBuffer;        // Save the config descriptor
  920.                 if (gStorageClassInfo.pFullConfigDescriptor == nil)
  921.                 {
  922.                     gConfigureStatus = kConfigureFailed;
  923.                     usbPB->usbRefcon = kReturnFromDriver;
  924.                     
  925.                     IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration - pointer is nil", usbPB->usbRefcon) );
  926.                 }
  927.                 break;
  928.                 
  929.             case kSetConfig:
  930.                 BlockCopy(    (void *) &gStorageClassInfo.pFullConfigDescriptor,
  931.                                 (void *) &gStorageClassInfo.partialConfigDescriptor,
  932.                                 (Size) (sizeof(USBConfigurationDescriptor) ) );
  933.                 
  934.                 for (i=0; i < gStorageClassInfo.partialConfigDescriptor.numInterfaces; i++)
  935.                 {
  936.                     gStorageClassInfo.interfaceRefArray[i] = 0;
  937.                     
  938.                     GetInterfaceDescriptor(    gStorageClassInfo.pFullConfigDescriptor,
  939.                                                     i,
  940.                                                     &pInterfaceDescriptor);
  941.                     BlockCopy(    (void *)pInterfaceDescriptor,
  942.                                     (void *)(&(gStorageClassInfo.interfaceDescriptors[i])),
  943.                                     (Size)(pInterfaceDescriptor->length));
  944.                 }
  945.                 
  946.                 gStorageClassInfo.pInterfaceDescriptor = &(gStorageClassInfo.interfaceDescriptors[0]);
  947.                 
  948.                 gStorageClassInfo.interfaceIndex =        0;
  949.                 gStorageClassInfo.interfaceCount =        gStorageClassInfo.partialConfigDescriptor.numInterfaces;
  950.                 usbPB->usbRefcon =                            kFindStorageInterface;
  951.                 break;
  952.                 
  953.             case kFindStorageInterface:
  954.                 gStorageClassInfo.interfaceNumber =        usbPB->usbWIndex;
  955.                 usbPB->usbRefcon =                            kNewInterfaceRef;
  956.                 break;
  957.                 
  958.             case kNewInterfaceRef:
  959.                 gStorageClassInfo.interfaceRef =        usbPB->usbReference;
  960.                 usbPB->usbRefcon =                        kStorageConfigureInterface;
  961.                 break;
  962.                 
  963.             case kStorageConfigureInterface:
  964.                 usbPB->usbRefcon = kStorageFindInterruptPipe;
  965.                 break;
  966.             
  967.             case kStorageFindInterruptPipe:                                
  968.                 gStorageClassInfo.interruptPipeRef =     usbPB->usbReference;
  969.                 usbPB->usbRefcon =                            kStorageFindBulkInPipe;
  970.                 break;
  971.                 
  972.             case kStorageFindBulkInPipe:
  973.                 gStorageClassInfo.readPipeRef =     usbPB->usbReference;
  974.                 usbPB->usbRefcon =                    kStorageFindBulkOutPipe;
  975.                 break;
  976.             
  977.             case kStorageFindBulkOutPipe:
  978.                 gStorageClassInfo.writePipeRef = usbPB->usbReference;
  979.                 usbPB->usbRefcon =                     kStorageReadFirmwareVersion;
  980.                 
  981.                 gConfigured = true;                                // Set the configured flag so we can respond to calls via the dispatch table
  982.                 gConfigureStatus = kConfigureComplete;        // Flag for client to determine that we are no configured
  983.                 IF_DEBUG(USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: Driver Configured.", 3 ) );            
  984.                 usbPB->usbRefcon = kReturnFromDriver;
  985.                 break;
  986.             
  987.             case kStorageReadFirmwareVersion:
  988.                 gConfigured = true;                                // Set the configured flag so we can respond to calls via the dispatch table
  989.                 gConfigureStatus = kConfigureComplete;        // Flag for client to determine if we are configured
  990.                 IF_DEBUG(USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: Driver Configured.", 3 ) );            
  991.                 usbPB->usbRefcon = kReturnFromDriver;
  992.                 break;
  993.                 
  994.             case kStorageReadInterrupt:    
  995.     //            ProcessStorageInterrupt(pStoragePB);
  996.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 0:", gStorageClassInfo.interruptReport[0] ));
  997.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 1:", gStorageClassInfo.interruptReport[1] ));
  998.                 
  999.                 usbPB->usbRefcon = kStorageReadInterrupt;
  1000.                 break;
  1001.     
  1002.             case kNilCompletion:
  1003.             default:
  1004.                 if ( usbPB->usbStatus == noErr )
  1005.                     usbPB->usbRefcon = kUndefined | kReturnFromDriver;
  1006.                 break;
  1007.         }
  1008.     }
  1009.     
  1010.     if ( usbPB->usbStatus == noErr )
  1011.     {
  1012.         if (!(usbPB->usbRefcon & kReturnFromDriver))
  1013.             StorageDeviceInitiateConfiguration(usbPB);
  1014.     }
  1015.     else
  1016.     {
  1017.         gConfigureStatus = kConfigureFailed;
  1018.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, StateStr(usbPB->usbRefcon, kPString), usbPB->usbRefcon) );
  1019.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, USBStatusStr(usbPB->usbStatus, kPString), 0) );
  1020.     }
  1021. }
  1022.  
  1023.  
  1024. void 
  1025. StorageDriverEntry(    USBDeviceRef                    deviceRef,
  1026.                             USBDeviceDescriptorPtr        deviceDescriptorPtr,
  1027.                             USBInterfaceDescriptorPtr    pInterfaceDescriptor)
  1028. {
  1029.     UInt32    usbVersion;
  1030.             
  1031.     IF_DEBUG( USBExpertStatus(deviceRef, "\pStorage Driver Entry" , 1 ) );
  1032.     
  1033.     if( !gBeenThereDoneThat)
  1034.     {
  1035.         gBeenThereDoneThat = true;
  1036.         
  1037.         // Check for the correct version of the USB manager.
  1038.         // We are ok with all version later than 1.0
  1039.         
  1040.         if (GetUSBVersion(&usbVersion) == noErr)
  1041.         {
  1042.             if ((usbVersion & 0xffff0000) < 0x01010000)        // Wrong USB version number so do NOT continue
  1043.             {
  1044.                 IF_DEBUG( USBExpertStatus(deviceRef, "\pWrong version of the USB Manager" , 1 ) );
  1045.                                 
  1046.                 IF_DEBUG( USBExpertFatalError(deviceRef, 0, "\pWrong USB Manager version" , 0) );
  1047.                 gConfigured = false;                                // Set the configured flag so we can respond to calls via the dispatch table
  1048.                 gConfigureStatus = kConfigureFailed;        // Flag for client to determine that configuration failed
  1049.                 
  1050.                 return ;
  1051.             }
  1052.         }
  1053.         
  1054.         // Initialize the global data structures
  1055.         BlockZero(&gStorageClassInfo, sizeof(StorageClassInfo));
  1056.         BlockZero(&gInterruptPB, sizeof(StorageClassTransactionPB));
  1057.         BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  1058.         
  1059.         gStorageClassInfo.retryCount =                kStorageRetryCount;
  1060.         gStorageClassInfo.deviceDescriptor =        *deviceDescriptorPtr;        // keep a copy of the device descriptor
  1061.         gStorageClassInfo.pInterfaceDescriptor =    pInterfaceDescriptor;
  1062.         gStorageClassInfo.deviceRef =                    deviceRef;
  1063.         gStorageClassInfo.interfaceRef =                deviceRef;
  1064.         gStorageClassInfo.transDepth =                0;                                    // init Delay Callback Depth
  1065.  
  1066.         InitParamBlock( deviceRef, &gStorageClassInfo.usbPB );
  1067.                 
  1068.         //    Start out at first state
  1069.         if (gStorageClassInfo.pInterfaceDescriptor != NULL)
  1070.         {
  1071.             gStorageClassInfo.usbPB.usbRefcon = kStorageConfigureInterface;
  1072.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as interface driver" , 0 ) );
  1073.         }
  1074.         else
  1075.         {
  1076.             gStorageClassInfo.usbPB.usbRefcon = kGetFullConfiguration0;
  1077.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as device driver" , 0 ) );
  1078.         }
  1079.         
  1080.         gConfigureStatus = kConfigureInProgress;
  1081.         StorageDeviceInitiateConfiguration(&gStorageClassInfo.usbPB);
  1082.     }
  1083. }
  1084.  
  1085.  
  1086. void
  1087. StorageClassDriverFinalize( void )
  1088. {
  1089. OSStatus    status;
  1090.  
  1091.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverFinalize." , 0 ) );
  1092.     
  1093.     //
  1094.     // Make sure all pipes are finished with transactions by calling the USBAbortPipeByReference function
  1095.     //
  1096.     status = USBAbortPipeByReference(gStorageClassInfo.deviceRef);                // Control pipe
  1097.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Control pipe" , status ) );
  1098.     
  1099.     status = USBAbortPipeByReference(gStorageClassInfo.interruptPipeRef);    // Interrupt pipe
  1100.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Interrupt pipe" , status ) );
  1101.     
  1102.     status = USBAbortPipeByReference(gStorageClassInfo.readPipeRef);            // Read pipe
  1103.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Read pipe" , status ) );
  1104.     
  1105.     status = USBAbortPipeByReference(gStorageClassInfo.writePipeRef);            // Write pipe
  1106.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Write pipe" , status ) );
  1107. }
  1108.  
  1109.  
  1110. OSStatus    
  1111. StorageClassDriverNotifyProc(UInt32    notification, void* pointer)
  1112. {
  1113. #pragma unused (notification, pointer)
  1114. OSStatus status = noErr;
  1115.         
  1116.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gConfigureStatus: " , gConfigureStatus ) );
  1117.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gOKToRemoval: " , gOKToRemoval ) );
  1118.     
  1119.     // Don't allow removal if we are busy configuration the interface.
  1120.     if (gConfigureStatus == kConfigureInProgress)
  1121.     {
  1122.         status = kUSBDeviceBusy;
  1123.     }
  1124.     
  1125.     // Don't allow removal until the Shim says it's ok
  1126.     if (gOKToRemoval == false)
  1127.     {
  1128.         status = kUSBDeviceBusy;
  1129.     }
  1130.     
  1131.     return (status);
  1132. }
  1133.